#include "tcp_thread.h"

TCP_Thread::TCP_Thread(QObject *parent) : QObject(parent)
{
    //创建套接字
    sockfd = new QTcpSocket(this);

    connect(sockfd,&QTcpSocket::connected,this,[=](){
        MYLOG << "QThread ID:" <<QThread::currentThreadId() <<"成功与服务器建立连接";
        g_bTcpStateFlag = true;
        emit s_connectSuccess();
    });

    connect(sockfd,&QTcpSocket::disconnected,this,[=](){
        MYLOG << "QThread ID:" <<QThread::currentThreadId() <<"与服务器断开连接";
        emit s_disconnected();
    });

    connect(sockfd,&QTcpSocket::readyRead,this,&TCP_Thread::RecvMsg);
}

//DEBUG打印数据包
static void PrintMsg(MsgStruct *msg)
{
    if(msg){};//消除变量未使用警告
    #ifdef DEBUG
    qDebug("Msg version:0x%x  ", msg->version);
    qDebug("Msg header_len:0x%x  ", msg->header_len);
    qDebug("Msg encrypt_type:0x%x  ", msg->encrypt_type);
    qDebug("Msg protocol_type:0x%x  ", msg->protocol_type);
    qDebug("Msg total_len:0x%x  ", msg->total_len);
    qDebug("Msg date_type:0x%x  ", msg->data_type);
    qDebug("Msg seq_num:0x%x  ", msg->seq_num);
    qDebug("Msg frag_flag:0x%x  ", msg->frag_flag);
    qDebug("Msg frag_offset:0x%x  ", msg->frag_offset);
    qDebug("Msg custom1:0x%x  ", msg->custom1);
    qDebug("Msg custom2:0x%x  ", msg->custom2);
    qDebug("Msg header_chk:0x%x  ", msg->header_chk);
    qDebug("Msg source_addr:0x%x  ", msg->source_addr);
    qDebug("Msg target_addr:0x%x  ", msg->target_addr);
    for(int i = 0; i < msg->total_len-msg->header_len; i++)
    {
       qDebug("Msg data[%d]:0x%x  ", i, msg->data[i]);
    }
    #endif
}

//数据包序列号生成
static int GetCurSeq(void)
{
    static int cur_seq = 0;
    cur_seq++;
    if(cur_seq >= 0xFF)
    {
        cur_seq = 0;
    }
    return cur_seq;
}

//数据包长度核验
static int GetChkSum(char* data, int dataLen)
{
    int sum = 0;
    for(int i = 0; i < dataLen; i++)
    {
        sum += data[i];
    }
    return sum;
}

//连接至服务器
void TCP_Thread::ConnectToServer(QString ip, qint16 port)
{
    sockfd->connectToHost(QHostAddress(ip),port);
}

//将主线程传来的数据包发送至服务器
void TCP_Thread::SendMsg(QVariant msg)
{
    MsgStruct sendMsg;
    QByteArray sendData;
    memset(&sendMsg,0X0,sizeof (MsgStruct));
    sendMsg = msg.value<MsgStruct>();
    if(sendMsg.seq_num != 0)//若为0，不进行核验
    {
        g_iPreSeq = GetCurSeq();//获取序列号
        sendMsg.seq_num = g_iPreSeq;
    }else
    {
        g_iPreSeq = 0;
    }
    sendMsg.header_chk = GetChkSum((char*)(&sendMsg), MSG_HEADER_STABLE_LEN);
    sendData.resize(sizeof(sendMsg));
    memcpy((void *)sendData.data(), (void *)&sendMsg, sizeof(sendMsg));
    PrintMsg(&sendMsg);
    //发送信息
    if(-1 == sockfd->write(sendData)){
        emit s_wrongMsg(QString("send fail"),QString("Please cheack connect"));
        return;
    };
    MYLOG << "QThread ID:" <<QThread::currentThreadId() <<"MSG Send Success";
}

//将TCP获取到的数据包发送至主线程
void TCP_Thread::RecvMsg()
{
    MYLOG << "QThread ID:" <<QThread::currentThreadId() <<"MSG Recv Success";
    MsgStruct recvMsg;
    QByteArray recvData;
    QVariant emitToMainMsg;
    recvData = sockfd->readAll();
    memcpy((void *)&recvMsg,(void *)recvData.data(), sizeof(recvMsg));
    PrintMsg(&recvMsg);

    //核验包数据
    if(g_iPreSeq != 0)//若不为0，进行核验
    {
        if(recvMsg.seq_num != g_iPreSeq)
        {
            MYLOG << "seq error:" << recvMsg.seq_num<< "; preSeq:" << g_iPreSeq;
            emit s_wrongMsg(QString("recv fail"),QString("Please cheack connect"));
            g_iPreSeq = 0;

            return;
        }else
        {
            g_iPreSeq = 0;
        }
    }
    if(recvMsg.version != MSG_VERSION)
    {
        MYLOG << "version error: "<< recvMsg.version ;
        emit s_wrongMsg(QString("recv fail"),QString("Please cheack connect"));
        return;
    }
    if(recvMsg.encrypt_type != MSG_ENCRYPT_NONE)
    {
        MYLOG << "encrypt_type error:" << recvMsg.encrypt_type;
        emit s_wrongMsg(QString("recv fail"),QString("Please cheack connect"));
        return;
    }
    if(recvMsg.protocol_type != MSG_PROTOCOL_S2C)
    {
        MYLOG << "protocol_type error:" << recvMsg.protocol_type;
        emit s_wrongMsg(QString("recv fail"),QString("Please cheack connect"));
        return;
    }
    if(recvMsg.frag_flag != MSG_FLAG_FRAG_NO)
    {
        MYLOG << "frag_flag error:" << recvMsg.frag_flag;
        emit s_wrongMsg(QString("recv fail"),QString("Please cheack connect"));
        return;
    }
    if(recvMsg.header_chk != GetChkSum((char*)(&recvMsg), recvMsg.header_len))
    {
        MYLOG << "header_chk error:" << recvMsg.header_chk;
        emit s_wrongMsg(QString("recv fail"),QString("Please cheack connect"));
        return;
    }
    emitToMainMsg.setValue(recvMsg);
    emit s_recvMsg(emitToMainMsg);
}

//关闭TCP连接
void TCP_Thread::CloseTCP()
{
    g_bTcpStateFlag = false;
    sockfd->disconnectFromHost();
    if(sockfd->state() != QAbstractSocket::UnconnectedState)
    {
        sockfd->waitForDisconnected();
    }
    emit s_closeTCPSuccess();
}

TCP_Thread::~TCP_Thread()
{
    CloseTCP();

    delete sockfd;
}
